/*
 * cluster.c
 *
 *  Created on: 20/09/2011
 *      Author: utn_so
 */

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "utils.h"
#include <ctype.h>
#include "estaticas.h"
#include "colas.h"
#include "pilassub.h"
#include "iniciarFat.h"
#include "direccionamiento.h"
#include "cluster.h"




//struct colaClusterLibres *clustersLibres; /* GLOBAL */




/* pregunta si el cluster libre*/
uint32_t EsLibre(struct cluster iClus){

	/***Vamos a recorrer la lista con la intención de fijarnos si un cluster está libre.
	 * Sabremos si está libre cuando encontremos el número de cluster.
	 * Caso contrario, estará ocupado****/
	struct nodoColaClusterLibres *nodo;
	pthread_mutex_lock(&mutexClustersLibres);
	nodo = clustersLibres->frente;
	while (nodo != 0){  // ¿ 0 es igual a NULL ?

		if (nodo->numero == iClus.numero){

			//Si son iguales implica que lo encontró así que ese cluster ESTA LIBRE
			return 1;
		}
		nodo = nodo->sgte;
	}

	pthread_mutex_unlock(&mutexClustersLibres);

	return 0;

}
// struct colaCluster *clustersLibres; **** GLOBAL, definida más arriba*/

uint32_t CrearColaClusterLibres() // retorna la cantidad de cluster libres
{
	/*
	 * Crea la cola que guarda el número de cluster, de todos los clusters libres.
	 */
	uint32_t i;

	pthread_mutex_lock(&mutexClustersLibres);

	clustersLibres = (struct colaClusterLibres *) malloc (sizeof(struct colaClusterLibres));
	clustersLibres->frente = NULL;
	clustersLibres->final = NULL;
	clustersLibres->cantidadNodosLibres = 0;
											/*cantidad de direccionamientos en un sector. El 4 es por que son direcciones de 4 bytes */
	pthread_mutex_lock(&mutexFat);
	for (i = 2; i < (bootSector->sectoresPorFat * (bootSector->bytesPorSector/4) ) ; i++)
	{
		if ( (fat[i]) == 0 )
		{
			MeterEnColaClusterLibres(clustersLibres, i);

		}
	}
	pthread_mutex_unlock(&mutexFat);

	pthread_mutex_unlock(&mutexClustersLibres);

	return clustersLibres->cantidadNodosLibres; //saque ++. porqué tenía el ++???
}



uint32_t NotEndCluster(uint32_t iClus) {
	if (iClus >= EOC_MINIMO && iClus <= EOC_MAXIMO)
		return 0;
	else
		return 1;

};

struct colaCluster *CrearColaClusterDeEntradasDirectorio (struct cluster *clustersEntradaDirectorio){
	/*
	 * Dado un numero de cluster, retorna una cola de numeros de clusters en orden del archivo o de la carpeta
	 * del cluster inicial
	 */

	struct colaCluster *cola;		//FIXME cambiar el struct cluster por un uint32_t
//	CrearColaCluster(cola);
	cola = (struct colaCluster *) malloc (sizeof(struct colaCluster));
	cola->frente = NULL;
	cola->final = NULL;
	uint32_t i = 0;
	i = clustersEntradaDirectorio->numero;

	MeterEnColaCluster(cola, i);
	pthread_mutex_lock(&mutexFat);
	while (NotEndCluster(fat[i])) { //antes era: while (NotEndCluster(clustersEntradaDirectorio->numero)){
		i = fat[i];
		MeterEnColaCluster(cola, i);
	}
	pthread_mutex_unlock(&mutexFat);
	return cola;

};

void RecorrerColaClusterParaCrearListaDeArchivos (struct colaCluster *cola, struct colaArchivos *colaArchivo /*Debe ser inicializada antes*/,struct nodoPilaDirectorio *pila)
{	/* ya no se usa */

	/*FIXME
	 * RecorrerColaClusterParaCrearListaDeArchivos debería
	 * 0) Agregar un campo en el nodo de la colaArchivos que sea esCarpeta;

		1) Recorrer la cola de archivos
		1.1) identificar los directorios
		1.2) agregar al directorio en la pila de subdirectorios
		1.3) Sacar un nodo de la pila de subdirectorios
		1.4) Armar la Cola de Archivos, y empezar desde 1)
	*/



//	uint32_t tamanoCluster = bootSector->bytesPorSector * bootSector->sectoresPorCluster;

	CrearColaArchivos(colaArchivo); //debe ser inicializada antes de la función
	pila = CrearPilaDirectorio();

	char *entrada;
	entrada = (char *) malloc (32);
	char *nombre;
	nombre = (char *) malloc (14);


	//cantidad de entradas de directorio por cluster
	uint32_t cantidadEntradas = (bootSector->sectoresPorCluster * bootSector->bytesPorSector) / 32; /* Cantidad de entradas en un cluster */

	uint32_t posCluster;


//	struct cluster clus;
	char *carpeta;

	uint32_t cantNodosCola = CantidadDeNodosCola (cola);
	carpeta = (char *) malloc (bootSector->sectoresPorCluster * bootSector->bytesPorSector * cantNodosCola);


	char esCarpeta=0;

	uint32_t j;
	for (j = 0; j < (cantidadEntradas * cantNodosCola) ; j++) {

		//FIXME agregar qué pasa si una entrada fue borrada

		carpeta = ObternerCarpetaDeEntradasDeDirectorio( cola );
		memcpy(entrada, (carpeta + (32 * j)), 32);

		if(!EstaBorrado(entrada)){
			esCarpeta=0;



			if (EsCarpeta(entrada))
	 	 	{

					posCluster = UbicacionCarpeta(entrada);
					nombre = leerNombre(entrada);
//					ApilarDirectorio(pila, posCluster);
					esCarpeta=1;
					MeterEnColaArchivos(colaArchivo, nombre, esCarpeta);

	 	 	}

			if (EsArchivo(entrada))
			{
				nombre = leerNombre(entrada);
				MeterEnColaArchivos(colaArchivo, nombre, esCarpeta);
			}

			if  (EsLongFileName(entrada))
			{
					nombre = leerNombreLargo(entrada);
					j++;
					memcpy(entrada, (carpeta + (32 * j)), 32);
					if (EsCarpeta(entrada))
			 	 	{
							posCluster = UbicacionCarpeta(entrada);
							nombre = leerNombre(entrada);
							ApilarDirectorio(pila, posCluster);
							MeterEnColaArchivos(colaArchivo, nombre, esCarpeta);
			 	 	}

					if (EsArchivo(entrada))
					{
						nombre = leerNombre(entrada);
						MeterEnColaArchivos(colaArchivo, nombre, esCarpeta);
					}

			}
		}


		} /* end for */

}



char EsArchivo(char *entrada){

	if ( *(entrada+11) == ATRIBUTO_ARCHIVO)
		return 1;
	else
		return 0;
}

char EsLongFileName(char *entrada){

	if ( *(entrada + 11) == ATRIBUTO_LFN)
		return 1;
	else
		return 0;
};

char EstaBorrado(char *entrada)
{
	if ( *(entrada) == ATRIBUTO_BORRADO1 || *(entrada) == ATRIBUTO_BORRADO2)
			return 1;
		else
			return 0;
}


uint32_t ObtenerClusterDeDirectorio(char *path_original)
{
	/*
	 * Dado el path de un archivo o directorio, retorna el numero
	 * de cluster en donde inicia el archivo o directorio.
	 *
	 * Si path = "/" retorna el nº cluster directorio raiz (2)
	 * Si path = "/archivo" retorna nº de cluster del directorio raiz (2)
	 * si path = "/dir1 retorna nº de cluster de dir1
	 * si path = "/dir1/dir2 retorna nº de cluster de dir1
	 * si path = "/dir1/archivo retorna nº de cluster de dir1
	 * si el path no existe retorna 0
	 */

	//uint32_t clusterEntradaRaiz = 2; //debe ser variable global
	char *path;
	path = (char *) malloc (strlen(path_original)+1);
	strcpy(path, path_original);

	struct cluster *iClus;
	iClus = (struct cluster *) malloc (sizeof(struct cluster));
	iClus->numero = bootSector->clusterRaiz;

	if (strcmp(path,"/") == 0)
	{
		uint32_t numeroCluster = iClus->numero;
		free(iClus);
		free(path);
		return numeroCluster;
	}

	uint32_t j;
	char *dir;
//	dir = (char *) malloc (14);

	char *nombre;
	nombre = (char *) malloc (14);

	char *entrada;
	entrada = (char *) malloc (32); /* Entrada de directorio de 32 bytes */


	struct colaCluster *cola;
//	cola = (struct colaCluster *) malloc (sizeof(struct colaCluster));
	cola = CrearColaClusterDeEntradasDirectorio(iClus); // El 2 es cluster de Raiz

	uint32_t cantNodosCola = CantidadDeNodosCola (cola);
	char *carpeta;
//	carpeta = (char *) malloc (TAMANO_CLUSTER * cantNodosCola);


	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	while (cola->frente != NULL)
		SacarDeColaCluster(cola);
	free(cola);

	uint32_t cantidadEntradas = /*tamanoCluster*/ (bootSector->sectoresPorCluster * bootSector->bytesPorSector) * cantNodosCola / 32;  /* Entrada de directorio de 32 bytes */

	uint32_t posCluster = bootSector->clusterRaiz; //Igual a cero no encontró directorio sino el cluster del directorio
	uint32_t noEncontre, esArchivo;
	dir = strtok(path,"/"); 	// próximo strtok se usa: dir = strtok(NULL,"/");

	while (dir != NULL)
	{


		noEncontre = 1;

		for (j = 0; noEncontre && (j < cantidadEntradas) ; j++)
		{
			memcpy(entrada, (carpeta + (32 * j)), 32);


			if (*(entrada + 11) == ATRIBUTO_LFN)  /*(si entrada es nombre largo)*/
			{
				obtenerNombreLargo(entrada,nombre);

				if (strcmp(dir,nombre) == 0 && !EstaBorrado(entrada)) //si (el directorio es igual al nombre de la entrada)
				{
					j++;	//sumo j para avanzar a la próxima entrada
					memcpy(entrada, (carpeta + (32 * j)), 32);

					if (*(entrada + 11) == ATRIBUTO_DIRECTORIO) //es la entrada es carpeta obtengo el cluster
					{
						esArchivo = 0;
						noEncontre = 0;
					}
					else
					{
						esArchivo = 1;
						noEncontre = 0;
					}
				}
			}
			else
				if (*(entrada +11) == ATRIBUTO_DIRECTORIO && !EstaBorrado(entrada)) //si entrada es carpeta
				{	obtenerNombre(entrada, nombre);

					if (strcmp(dir,nombre) == 0)
					{
						esArchivo = 0;
						noEncontre = 0;
					}
					else
					{
						esArchivo = 0;
						noEncontre = 1;
					}
				}
/*

*/
		} //for


			if (noEncontre == 0)
			{
				if (esArchivo == 0) /*entonces es directorio */
				{
					posCluster = UbicacionCarpeta(entrada);
					iClus->numero = posCluster;

					cola = CrearColaClusterDeEntradasDirectorio(iClus);
					free(carpeta);
					carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

					cantNodosCola = CantidadDeNodosCola(cola);
					cantidadEntradas = TAMANO_CLUSTER * cantNodosCola / 32;
					while (cola->frente != NULL)
							SacarDeColaCluster(cola);
					free(cola);
					dir = strtok(NULL,"/");
					if (dir == NULL)
					{
						free(carpeta);
						free (entrada);
						free(nombre);
						free(iClus);
						free(path);
						return posCluster;
					}

				}
				else
				{
					dir = strtok(NULL,"/");
					if (dir != NULL)
					{
						free(carpeta);
						free (entrada);
						free(nombre);
						free(iClus);
						free(path);
						return 0;
					}
					else
					{
						free(carpeta);
						free (entrada);
						free(nombre);
						free(iClus);
						free(path);
						return posCluster;	//entrando por acá posCluster es el directorio anterior del archivo
					}
				}
			}
			else
			{	/*return 0*/
				dir = strtok (NULL,"/");
				if (dir == NULL)
				{
					free(carpeta);
					free (entrada);
					free(nombre);
					free(iClus);
					free(path);
					return posCluster;
				}
				else
				{
					free(carpeta);
					free (entrada);
					free(nombre);
					free(iClus);
					free(path);
					return 0;
				}
			}




	} //while
	free(carpeta);
	free (entrada);
	free(nombre);
	free(iClus);
	free(path);
	return 0; //EL directorio no existe

}




uint32_t CantidadDeNodosCola (struct colaCluster *cola) //devuelve la cantidad de nodos que tiene colaCluster (cada nodo es un cluster)
{
	/*
	 * Retorna la cantidad de nodo que tiene una cola de Clusters
	 */

	uint32_t j; //contador
	j = 0;
	struct nodoColaCluster *ptr;

	ptr = cola->frente;

	while (ptr != NULL)
	{
		j++;
		ptr = ptr->sgte;
	}
	return j;

}

char *leerNombre(char *entrada) // devuelve un puntero al nombre de archivo o directorio en una entrada
{
	/*
	 * Dada una entrada común (no LFN), retorna el nombre del archivo "8.3"
	 */
	char *nombre, *extension, *nombreCompleto;
	nombreCompleto = (char *) malloc (13); //"12345678.ext"
	nombre = (char *) malloc (9); // "12345678"
	extension = (char *) malloc (4); // "ext"

	memcpy (nombre,entrada,8);
	memcpy (extension, (entrada + 8), 3);

	memcpy(nombreCompleto, nombre, 8);

	memcpy( (nombreCompleto + 8) ,".",1);
	strcat(nombreCompleto,extension);

	return nombreCompleto;
}

char *leerNombreLargo(char *entrada) // devuelve un puntero al nombre largo de archivo o directorio en una entrada
{
	/*
	* Dada una entrada LFN, retorna el nombre del archivo.
	*/

//	char *nombre1_utf16, *nombre2_utf16, nombre3_utf16;
	char *nombreCompleto = (char *) malloc (27);
/*
 	nombre1_utf16 = (char *) malloc (11);
	nombre2_utf16 = (char *) malloc (13);
	nombre3_utf16 = (char *) malloc (5);
*/

	memcpy(nombreCompleto , (entrada+1),10);
	memcpy((nombreCompleto + 10), (entrada+15),12);
	memcpy((nombreCompleto + 10 + 12), (entrada+28),4);
	memcpy((nombreCompleto + 10 + 12 + 1), "/0",1);



	/*return	unicode_utf16_to_utf8( nombreCompleto, strlen(nombreCompleto), size);*/
	return nombreCompleto;



}


//también valido para entradas de  archivo
uint32_t UbicacionCarpeta(char *entrada) /*retorna la ubicacion de la entrada de directorio de un archivo o carpeta */
{
	/*
	 * Dada una entrada de directorio común, retorna el cluster inicial en donde está ubicado.
	 */

	uint32_t baja=0;
	uint32_t alta=0;
	uint32_t posicion = 0;

	memcpy( &alta, entrada + 20, 2);
	memcpy( &baja, entrada + 26, 2);

	posicion = (alta*256) + baja;
//	posicion = (alta<<16) | baja;

	return posicion;
}


uint32_t AgregarUnClusterLibreAColaDeCluster(struct colaCluster *cola)
{
	/*
	 * Agrega un cluster Libre al final de la cola de cluster.
	 * Además actualiza la fat.
	 */

	uint32_t clusterLibre, temp;
	clusterLibre = SacarDeColaClusterLibres(clustersLibres);

	if (!ColaClusterVacia(*cola))
	{
		temp = cola->final->numero;

		MeterEnColaCluster(cola, clusterLibre);

		limpiarClusterEnDisco(clusterLibre);

		pthread_mutex_lock(&mutexFat);
		fat[clusterLibre] = LAST_CLUSTER_IN_FILE;
		fat[temp] = clusterLibre;
		pthread_mutex_unlock(&mutexFat);
	}
	if (ColaClusterVacia(*cola))
	{
		MeterEnColaCluster(cola, clusterLibre);
		limpiarClusterEnDisco(clusterLibre);

		pthread_mutex_lock(&mutexFat);
		fat[clusterLibre] = LAST_CLUSTER_IN_FILE;
		pthread_mutex_unlock(&mutexFat);
	}
	return clusterLibre;
}

uint32_t RemoverUltimoClusterDeColaDeCluster(struct colaCluster *cola) /* Remueve un cluster de la cola de clusters y lo pasa a la cola de clustersLibres */
{
	/*
	 *  Elimina un cluster del final de la cola de cluster.
	 *  Además actualiza la fat.
	 */

	uint32_t clusterRemovido;
	struct nodoColaCluster *nodo, *nodoAux;

	nodo = cola->frente;

	if (nodo == NULL) /* la cola no tiene cluster */
									/*  Si es el único cluster entonces NO HAY QUE PONERLO COMO LIBRE*/
		return 0;

/*
	if (nodo == cola->final) // la cola tiene un solo cluster
	{
		MeterEnColaClusterLibres(clustersLibres, nodo->numero);
		fat[nodo->numero] = FREE_CLUSTER;
		return SacarDeColaCluster(cola);
	}
*/
	if (cola->frente == cola->final)
	{
		pthread_mutex_lock(&mutexClustersLibres);
		MeterEnColaClusterLibres(clustersLibres, cola->frente->numero);
		pthread_mutex_unlock(&mutexClustersLibres);
		nodoAux = cola->frente;
		pthread_mutex_lock(&mutexFat);
		fat[cola->frente->numero] = FREE_CLUSTER;
		pthread_mutex_unlock(&mutexFat);
		cola->frente = NULL;
		cola->final = NULL;
		clusterRemovido = nodoAux->numero;
		free(nodoAux);

		return clusterRemovido;


	}

	while ( !(nodo->sgte == cola->final) )
		nodo = nodo->sgte;

	nodoAux = nodo->sgte;
	pthread_mutex_unlock(&mutexClustersLibres);
	MeterEnColaClusterLibres(clustersLibres, nodoAux->numero);
	pthread_mutex_unlock(&mutexClustersLibres);
	cola->final = nodo;
	cola->final->sgte = NULL;
	pthread_mutex_lock(&mutexFat);
	fat[cola->final->numero] = LAST_CLUSTER_IN_FILE;
	fat[nodoAux->numero] = FREE_CLUSTER;

	pthread_mutex_unlock(&mutexFat);
	clusterRemovido = nodoAux->numero;
	free(nodoAux);


	return clusterRemovido;
}


/* Devuelve 1 si remueve el cluster número iClus. Devuelve 0 si el cluster no existe en la cola */
uint32_t RemoverUnClusterDeColaDeCluster(struct colaCluster *cola, uint32_t iClus)
{
	/* no se usa */

	struct nodoColaCluster *nodo, *nodoAux;
	nodo = cola->frente;

	if (nodo == NULL) /* la cola no tiene el cluster */
		return 0;

	if (nodo->numero == iClus)
	{
		pthread_mutex_lock(&mutexClustersLibres);
		MeterEnColaClusterLibres(clustersLibres, iClus);
		pthread_mutex_unlock(&mutexClustersLibres);
		cola->frente = nodo->sgte;
		pthread_mutex_lock(&mutexFat);
		fat[nodo->numero] = FREE_CLUSTER;
		pthread_mutex_unlock(&mutexFat);
		free (nodo);
		return 1;
	}


	while ( !(nodo->sgte->numero == iClus) || !(nodo->sgte == NULL) )
		nodo = nodo->sgte;

	if (nodo->sgte->numero == iClus)
	{
		pthread_mutex_lock(&mutexClustersLibres);
		MeterEnColaClusterLibres(clustersLibres,iClus);
		pthread_mutex_unlock(&mutexClustersLibres);
		nodo->sgte = nodo->sgte->sgte;
		nodoAux = nodo->sgte;
		pthread_mutex_lock(&mutexFat);
		fat[iClus] = FREE_CLUSTER;
		fat[nodo->numero] = nodo->sgte->numero;
		pthread_mutex_unlock(&mutexFat);

		free(nodoAux);

		return 1;
	}

	return 0;
}

struct nodoPilaDirectorio recorrerColaDeArchivos(){

	/* no se usa */

	struct colaCluster *cola = malloc(sizeof(struct colaCluster));
	struct colaArchivos *colaArchivo = malloc(sizeof(struct colaCluster));
	struct nodoPilaDirectorio *pila = malloc(sizeof(struct nodoPilaDirectorio));


	RecorrerColaClusterParaCrearListaDeArchivos(cola, colaArchivo, pila);

	while(pila->sgte!=NULL){
		//Debo recorrer toda la lista de directorios y volver a recorrerColaClusterParaCrearListaDeArchivos

	}
	return *pila;
}

uint32_t charToInt(char value){
	if(value == '1'){
		return 1;
	}
	if(value == '0'){
		return 0;
	}
	return -1;
}


char EsCarpeta(char *entrada){

	if ( *(entrada+11) == ATRIBUTO_DIRECTORIO)
		return '1';
	else
		return '0';
}


char *ObtenerEntradaDeArchivo(char *path_original, char *nombre, char *esDirectorio) // retorna la entrada de Directorio
  /*
   * Dado un path, lo busca en el arbol de directorios y retorna la entrada comun (no LFN)
   * Si el archivo es NOMBRE LARGO (LFN), char *nombre es el nombre del archivo
   * Sino (el nombre no es LFN) char *nombre es NULL.
   * El parámetro de entrada obtiene valor 1 ó 0 en caso que sea directorio o no
   */
{
	char *path;
	path = (char *) malloc (strlen(path_original) +1);
	strcpy (path, path_original);

	*esDirectorio = 0;
	uint32_t cd;
	cd = cantidadCarpetasDelPath(path);
	if (cd == -1)
	{
		*esDirectorio = 1;
		free (path);
		return NULL; //no existe el archivo
	}

	//uint32_t clusterEntradaRaiz = 2; //debe ser variable global
	struct cluster iClus;

	iClus.numero = bootSector->clusterRaiz;
/*
	if (!strcmp(path,"/"))
			return *iClus.numero;
*/

	char *archivo;
//	archivo = (char *) malloc (14);

/*	nombre = (char *) malloc (14); */ /* Lo debo hacer antes de la función */


	char *entrada;
	entrada = (char *) malloc (32); /* Entrada de directorio de 32 bytes */




	struct colaCluster *cola;
//	cola = (struct colaCluster *) malloc (sizeof(struct colaCluster));
	cola = CrearColaClusterDeEntradasDirectorio(&iClus); // El 2 es cluster de Raiz

	uint32_t cantNodosCola;
	cantNodosCola = CantidadDeNodosCola (cola);

	char *carpeta;
//	carpeta = (char *) malloc (TAMANO_CLUSTER * cantNodosCola);


	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	uint32_t cantidadEntradas = TAMANO_CLUSTER * cantNodosCola / 32;  /* Entrada de directorio de 32 bytes */

	uint32_t posCluster = 0; //Igual a cero no encontró directorio sino el cluster del directorio

	archivo = strtok(path,"/"); 	// próximo strtok se usa: dir = strtok(NULL,"/");
	int32_t i;
	for (i = 0; i < cd; i++)  //while (archivo != NULL)
	{

		*entrada = 1; // sólo para que entre en el siguiente for
		uint32_t noEncontre = 1;
		uint32_t j;
		for (j = 0; noEncontre && (j < cantidadEntradas) && *entrada != 0; j++)
		{
			memcpy(entrada, (carpeta + (32 * j)), 32);
	//		entrada = &(*(carpeta + (32*j))); //entrada se posiciona en la entrada número "j" de carpeta

			if (*(entrada +11) == ATRIBUTO_LFN)  /*(si entrada es nombre largo)*/{
				obtenerNombreLargo(entrada, nombre);
				if (strcmp(archivo,nombre) == 0) {	//si (el directorio es igual al nombre de la entrada)
					j++;	//sumo j para avanzar a la próxima entrada
					memcpy(entrada, (carpeta + (32 * j)), 32);
	//				entrada = &(*(carpeta + (32*j))); //avanzo a la próxima entrada
					if (*(entrada + 11) == ATRIBUTO_DIRECTORIO){ //es la entrada es carpeta obtengo el cluster
						noEncontre = 0;
					}
				}
			}
			else if (*(entrada +11) == ATRIBUTO_DIRECTORIO) {//si entrada es carpeta
				obtenerNombre(entrada, nombre);
				if (strcmp(archivo,nombre) == 0) {
					noEncontre = 0;
				}
			}

		}

			iClus.numero = UbicacionCarpeta(entrada);
			archivo = strtok(NULL,"/");
			cola = CrearColaClusterDeEntradasDirectorio(&iClus);
			free(carpeta);
			carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);
			cantNodosCola = CantidadDeNodosCola(cola);
			cantidadEntradas = TAMANO_CLUSTER * cantNodosCola / 32;



	} // for principal

	while (cola->frente != NULL)
		SacarDeColaCluster(cola);

	if (i == cd)
	{
		*entrada = 1; //para que entre en siguiente for
		uint32_t noEncontre = 1;
		uint32_t j;
		for (j = 0; noEncontre && (j < cantidadEntradas) && *entrada != 0 ; j++)
		{
			memcpy(entrada, (carpeta + (32 * j)), 32);
	//		entrada = &(*(carpeta + (32*j))); //entrada se posiciona en la entrada número "j" de carpeta

			if (*(entrada +11) == ATRIBUTO_LFN)  /*(si entrada es nombre largo)*/
			{
				obtenerNombreLargo(entrada, nombre);
				if (strcmp(archivo,nombre) == 0)
				{	//si (el directorio es igual al nombre de la entrada)
					j++;	//sumo j para avanzar a la próxima entrada
					memcpy(entrada, (carpeta + (32 * j)), 32);
	//				entrada = &(*(carpeta + (32*j))); //avanzo a la próxima entrada
					if (*(entrada + 11) == ATRIBUTO_ARCHIVO) //es la entrada es carpeta obtengo el cluster
					{
						if (!EstaBorrado(entrada))
						{
							free (cola);
							free (carpeta);
							free (path);
							return entrada;
						}
					}
					else
						*esDirectorio = 1;

				}
			}
			else

				if (*(entrada+11) == ATRIBUTO_ARCHIVO)
				{//si entrada es archivo
					obtenerNombre(entrada, nombre);
					if (strcmp(archivo,nombre) == 0)
						if (!EstaBorrado(entrada))
						{
							free (cola);
							free (carpeta);
							free (path);
							return entrada;
						}

				}

		}



		if (j == cantidadEntradas || *entrada == 0)
		{
			free (cola);
			free (carpeta);
			free (path);
			free (entrada);
			return NULL;
			/*iClus.numero = 0;
			return iClus.numero;*/  // SINO ENCONTRE LA CARPETA retorno 0
		}

	}


/*	iClus.numero = posCluster;
	return iClus.numero; */
	free (cola);
	free (carpeta);
	free (path);
	return entrada;

}


uint32_t cantidadCarpetasDelPath(char *path)
{
	/*
	 *   Cuenta la cantidad de directorios que contiene un path.
	 */

	if (strcmp(path,"/") == 0)
		return -1; //es un error porque "/" no es un archivo

	uint32_t cd;
	uint32_t cantidadNombres = 0;
	char *pathAuxiliar, *nombre;
	pathAuxiliar = (char *) malloc (strlen(path) + 1);
//	nombre = (char *) malloc (14);
	strcpy (pathAuxiliar, path);


	nombre = strtok(pathAuxiliar,"/");

	while (nombre != NULL)
	{
		cantidadNombres++;
		nombre = strtok(NULL,"/");
	}
	cd = cantidadNombres - 1;

	free(pathAuxiliar);
	free(nombre);
	return cd;
}

char *ObternerCarpetaDeEntradasDeDirectorio(struct colaCluster *cola)
{
	/*
	 * Dada una cola de Clusters de Directorio, retorna un char *, que componen todas las entradas
	 * de directorio de la cola.
	 */

	uint32_t cantCluster = CantidadDeNodosCola(cola);


	char *carpeta, *cluster;

//	carpeta = calloc(1, cantCluster * TAMANO_CLUSTER);
	carpeta = (char *) malloc (TAMANO_CLUSTER * cantCluster);
	memset(carpeta, 0, TAMANO_CLUSTER * cantCluster);

//	cluster =  (char *) malloc (TAMANO_CLUSTER);

	struct nodoColaCluster *ptr;

	uint32_t i;

	ptr = cola->frente;

	for (i = 0; ptr != NULL; i++)
	{
		cluster = SolicitarCluster(ptr->numero, 0);
		memcpy (carpeta + ( i * TAMANO_CLUSTER), cluster, TAMANO_CLUSTER);
		ptr = ptr->sgte;
		free(cluster);
	}



	return carpeta;
}

uint32_t contarCaracteres(char *path, char caracter)
{
	uint32_t i, length, cantidadCaracteres = 0;
	length = strlen(path);

	for (i = 0; i < length; i++)
	{
		if ( *(path + i) == caracter)
			cantidadCaracteres++;
	}

	return cantidadCaracteres;
}


uint32_t obtenerTamanoArchivo(char *entrada)
{
	uint32_t *size;
	size = (uint32_t *) (entrada + POSICION_SIZE_ENTRADA_DIRECTORIO); /* se probó y está bien */
	return *size;
}

void EscribirTamano(char *entrada, uint32_t size)
{
	char *posicion;
	posicion = (entrada + POSICION_SIZE_ENTRADA_DIRECTORIO); /* se probó y está bien */
	memcpy (posicion,&size, 4);
}

void EscribirEntrada(char *path, char *entrada)

/*
 * Dado el path de un archivo o directorio, ubica la carpeta,
 * genera la carpeta, le agrega la entrada de directorio.
 * Una vez agegada, escribe la carpeta (las entradas de directorio) en
 * el disco
 */

{
	uint32_t iClus, i, j, cantNodosCola, cantidadEntradas, numeroClusterEntrada, clusterEnCola;
	struct colaCluster *cola;
	struct nodoColaCluster *ptr;
	char *carpeta, *cluster, *nombre, *nombreAux;
	struct cluster auxCluster;

//	nombre = (char *) malloc (14);
	nombre = obtenerNombreArchivoPath(path);

	nombreAux = (char *) malloc (14);
	iClus = ObtenerClusterDeDirectorio(path);

	auxCluster.numero = iClus;
	cola = CrearColaClusterDeEntradasDirectorio(&auxCluster);

	cantNodosCola = CantidadDeNodosCola(cola);


//	carpeta = (char *) malloc (cantNodosCola * TAMANO_CLUSTER);

	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32;

	numeroClusterEntrada = UbicacionCarpeta(entrada);
	char noEncontre = 1;
	for ( i = 0; i < cantidadEntradas && noEncontre; i++)
	{
		obtenerNombreLargo(carpeta + (i* 32), nombreAux);
		if (strcmp(nombre, nombreAux) == 0 && !EstaBorrado(carpeta + ((i+1)* 32))) //uso i+1 porque como es entrada LFN me fijo en la siguiente si está borrada
		{
			noEncontre = 0;
		}

	}
	//Cuando encuentro la entrada y no está borrado, el for suma 1 para volver a evaluar.
	//Entonces ya me ubica en la entrada que debo escribir
	if (strcmp(nombre, nombreAux) == 0)
	{

		memcpy(carpeta + (i * 32), entrada, 32);
		clusterEnCola = i / 128;
		ptr = cola->frente;
		for (j = 0; j < clusterEnCola; j++)
			ptr = ptr->sgte;

		cluster = carpeta + (j * TAMANO_CLUSTER);
		enviarCluster(ptr->numero, cluster, 0);
	}
	else
	{/*error: no se encontró la entrada en el directorio */}

	struct nodoColaCluster *ptrAux;
	ptr = cola->frente;
	while (ptr != NULL)
	{
		ptrAux = ptr;
		ptr = ptr->sgte;
		free (ptrAux);
	}
	free(cola);

	free(nombreAux);
	free(carpeta);
	free(nombre);
}
/* por especificacion del tp los nombres no tendran espacios intermedios */
char *cambiarNombre (char *entrada, char *nombreNuevo) /* le cambia el nombre a una entrada común de 32 bytes */
{
	char *nombre, *ext, *entradaModificada;
	uint32_t size, i;
	entradaModificada = (char *) malloc (32);
	nombre = (char *) calloc (8+1,1); /* tamaño archivo es 8 y 1 es por char */
	ext = (char *) calloc (3+1,1); /* tamaño extensión de archivo es 8 y 1 es por char */



	memcpy(entradaModificada, entrada, 32);


	if(tieneExtension(nombreNuevo))
	{
		nombre = strtok (nombreNuevo, ".");
		ext = strtok (NULL,"\0");
		size = strlen(nombre);
		for (i = 0; i < size; i++)
			*(entradaModificada + i) = toupper(*(nombre + i));


		for (i = size; i < 8; i++)
			*(entradaModificada + i) = (char) 0;

		size = strlen(ext);
		for (i = 0; i < size; i++)
			*(entradaModificada + i + 8) = toupper(*(ext + i));

		for (i=size; i < 3;i++)
			*(entradaModificada + i + 8) = (char) 0;

	}
	else
	{
		nombre = strtok (nombreNuevo, "\0");

		size = strlen(nombre);
		for (i = 0; i < size; i++)
			*(entradaModificada + i) = toupper( *(nombre + i) );

		for (i = size; i < 8; i++)
			*(entradaModificada + i) = (char) 0;


		for (i = 8; i < 11; i++)
		{
			*(entradaModificada + i) = (char) 0; /* extensión vacía */
		}
	}


//	free(nombre);
//	free(ext);

	return entradaModificada;
}

/* por especificacion del tp los nombres no tendran espacios intermedios */
void obtenerNombre(char *entrada, char *nombre) /* retorna el nombre del archivo de entrad de 32bytes */
{
//	char *nombre	= (char *) calloc (11+1,1); /* tamaño archivo es 8 y 1 es por char */
	char *ext 		= (char *) calloc (3+1,1); /* tamaño extensión de archivo es 8 y 1 es por char */

	memcpy(nombre, entrada, 8);
	*(nombre + 8) = '\0';

	memcpy(ext, entrada + 8, 3);
	*(ext + 3) = '\0';

	if( *(ext)  !=  0)
	{
		strcat(nombre,".");
		strcat(nombre,ext);
	}

	free(ext);
	//return nombre;
}

uint32_t tieneExtension(char *nombreCorto)
{
	uint32_t i, puntos = 0, size;
	size = strlen(nombreCorto);

	for (i = 0; i < size; i++ )
	{
		if (*(nombreCorto + i) == '.')
			puntos++;
	}
	return puntos;
}

void borrarEntradaArchivo(char *path) /* marca la entrada del archivo como borrada */
										/* y envía el cluster al planificador para actualizar */
{
	uint32_t iClus, cantNodosCola, i, cantidadEntradas, clusterEnCola, j;
	char *carpeta, *entrada, *nombreLargo, *cluster, esDirectorio;

	entrada = (char *) malloc (32);
	nombreLargo = (char *) malloc (14);
	struct colaCluster *cola;
	struct nodoColaCluster *ptr;

	iClus = ObtenerClusterDeDirectorio(path);

	struct cluster *auxCluster = (struct cluster *) malloc (sizeof(struct cluster));
	auxCluster->numero = iClus;
	cola = CrearColaClusterDeEntradasDirectorio(auxCluster);
	cantNodosCola = CantidadDeNodosCola(cola);

	carpeta = (char *) malloc (cantNodosCola * TAMANO_CLUSTER);
	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32;

	entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esDirectorio); /* en este caso nombrLargo es NULL porque trabajo con nombre corto */

	for(i = 0; i < cantidadEntradas; i++)
	{
		if (memcmp(entrada, carpeta + (i * 32), 32) == 0) /* pregunta si son iguales */
		{
			*(carpeta + ( i * 32)) = ATRIBUTO_BORRADO1;

			clusterEnCola = i / 128;
			ptr = cola->frente;


			for (j = 0; j < clusterEnCola; j++)
				ptr = ptr->sgte;

			cluster = carpeta + (j * TAMANO_CLUSTER);
			enviarCluster(ptr->numero, cluster, 0);

			return;

		}

	}

	free(carpeta);
	free(entrada);
	free(auxCluster);
	return; /* no se encontró el archivo */
}

char *ArmarEntradaNombreLargo(char *entradaAnterior, char *nombreNuevo) /* en base a la entrada original de 32 bytes y un nombre (que puede ser LFN o no), arma una entrada LFN con el nuevo nombre */
{
	uint32_t length, i, size, j;

	char *entradaLarga;
	entradaLarga = (char *) malloc (64);


	uint16_t *utf1, *utf2, *utf3;
	utf1 = (uint16_t *) malloc(10);
	utf2 = (uint16_t *) malloc(12);
	utf3 = (uint16_t *) malloc(4);

	char *s1, *s2, *s3;
	s1 = calloc (5, 1);
	s2 = calloc (6, 1);
	s3 = calloc (2, 1);

	strncpy(s1, nombreNuevo, 5);
	strncpy(s2, nombreNuevo + 5, 6);
	strncpy(s3, nombreNuevo + 5 + 6, 2);


	unicode_utf8_to_utf16_inbuffer(s1, 5, utf1, &size);
	unicode_utf8_to_utf16_inbuffer(s2, 6, utf2, &size);
	unicode_utf8_to_utf16_inbuffer(s3, 2, utf3, &size);

	// CREO LA ENTRADA DE NOMBRE LARGO
	*(entradaLarga) = 'A';
	memcpy(entradaLarga + 1, utf1, 10);
	*(entradaLarga + 11) = ATRIBUTO_LFN; // ATRIBUTO_LFN
	*(entradaLarga + 12) = 0;
	*(entradaLarga + 13) = 0;
	memcpy(entradaLarga + 14, utf2, 12);
	memset(entradaLarga + 26,'0',2);
	memcpy(entradaLarga + 28, utf3, 4);

	//pego la entrada anterior de 32bytes al final de la entrada larga
	memcpy(entradaLarga + 32, entradaAnterior, 32);


	length = strlen(nombreNuevo);



	for (i = 0; i < 8 && i < length && *(nombreNuevo + i) != '.'; i++)
	{
		*(entradaLarga + 32 + i) = *(nombreNuevo + i);
	}

	if (i == length)
		for (i=length; i < 11; i++)
			*(entradaLarga + 32 + i) = 0;

	if (i == 8 && *(nombreNuevo + i) == 0)
		for (i = 8; i < 11; i++)
			*(entradaLarga + 32 + i) = 0;

	for (i = 8; i < length && *(nombreNuevo + i) != '.';i++ );
		if ( *(nombreNuevo + i) == '.')
		{
			for (j = i + 1; j < i+4;j++)

				if (*(nombreNuevo + j) != 0)
					*(entradaLarga + 32 + 8 + j-i-1) = *(nombreNuevo + j);
				else
					*(entradaLarga + 32 + 8 + j-i-1) = 0;
			return entradaLarga;
		}
	if (*(nombreNuevo + i) == '.')
	{	uint32_t comienzoExtension;
		comienzoExtension = i+1;

		for (; i < 8; i++)
			*(entradaLarga + 32 + i) = 0;


		for (i = 0; i < 3; i++)

			if (*(nombreNuevo + i) != 0)
				*(entradaLarga  + 32 + 8 + i) = *(nombreNuevo + comienzoExtension + i);
			else
				*(entradaLarga + 32 + 8 + i) = 0;
	}

	return entradaLarga;
}

void borrarEntradaArchivo_LFN(char *path) /* marca la entrada LFN del archivo como borrada. Marca la entrada comun y la de nombre largo como borradas */
{
	uint32_t iClus, cantNodosCola, i, cantidadEntradas, clusterEnCola1, clusterEnCola2, j;
	char *carpeta, *entrada, *nombreLargo, *entrada_LFN, *cluster1, *cluster2, esDirectorio;

	entrada = (char *) malloc (32);
	entrada_LFN = (char *) malloc (64);
	nombreLargo = (char *) malloc (13+1);


	struct colaCluster *cola;
	struct cluster *auxCluster = (struct cluster *) malloc (sizeof(struct cluster));
	struct nodoColaCluster *ptr;

	iClus = ObtenerClusterDeDirectorio(path);

	auxCluster->numero = iClus;
	cola = CrearColaClusterDeEntradasDirectorio(auxCluster);
	cantNodosCola = CantidadDeNodosCola(cola);

	carpeta = (char *) malloc (cantNodosCola * TAMANO_CLUSTER);
	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32;

	entrada = ObtenerEntradaDeArchivo(path, nombreLargo, &esDirectorio); /* en este caso nombrLargo es NULL porque trabajo con nombre corto */
	entrada_LFN = ArmarEntradaNombreLargo(entrada, nombreLargo);

	for(i = 0; i < cantidadEntradas; i++)
	{
		if (memcmp(entrada_LFN, carpeta + (i * 32), 64) == 0) /* pregunta si son iguales */
		{
			*(carpeta + ( i * 32)) = ATRIBUTO_BORRADO1;
			*(carpeta + ( (i + 1)* 32)) = ATRIBUTO_BORRADO1;

			clusterEnCola1 = i / 128;
			clusterEnCola2 = (i+1) / 128;
			ptr = cola->frente;

			for (j = 0; j < clusterEnCola1; j++)
				ptr = ptr->sgte;

			cluster1 = carpeta + (j * TAMANO_CLUSTER);
			enviarCluster(ptr->numero, cluster1, 0);

			cluster2 = NULL;
			if (clusterEnCola1 != clusterEnCola2)
			{
				cluster2 = carpeta + ((j + 1) * TAMANO_CLUSTER);
				enviarCluster(ptr->sgte->numero, cluster2, 0);
			}

			free(nombreLargo);
			free(entrada_LFN);
			free(carpeta);
			free(entrada);
			free(auxCluster);
			return;

		}

	}

	free(nombreLargo);
	free(entrada_LFN);
	free(carpeta);
	free(entrada);
	free(auxCluster);
	return; /* no se encontró el archivo */

}


void *obtenerNombreLargo(char *entrada, char *nombreLargo) /* retorna el nombre del archivo LFN */
{
	uint16_t *utf1, *utf2, *utf3;
	utf1 = (uint16_t *) malloc(10);
	utf2 = (uint16_t *) malloc(12);
	utf3 = (uint16_t *) malloc(4);

	char *s1, *s2, *s3;
	s1 = calloc(5+1, sizeof(char));
	s2 = calloc(6+1, sizeof(char));
	s3 = calloc(2+1, sizeof(char));

	//copio los pedazos de utf16 al una cadena de 2 bytes cada posición
	memcpy(utf1, entrada + 1, 10);
	memcpy(utf2, entrada + 14, 12);
	memcpy(utf3, entrada + 28, 4);


	//paso de utf16 a utf8 y guardo en s1, s2 y s3
	uint16_t size = 0;
	unicode_utf16_to_utf8_inbuffer(utf1, 10, s1, &size);
	unicode_utf16_to_utf8_inbuffer(utf2, 12, s2, &size);
	unicode_utf16_to_utf8_inbuffer(utf3, 4, s3, &size);
	*(s1 + 5) = 0;
	*(s2 + 6) = 0;
	*(s3 + 2) = 0;

	//concateno el nombre con s1+s2+s3 y '\0' al final
//	char *nombreLargo;
//	nombreLargo = (char *) malloc(140);
	memcpy(nombreLargo, s1, 5);
	memcpy(nombreLargo + 5, s2, 6);
	memcpy(nombreLargo + 11, s3, 2);
	*(nombreLargo + 13) = '\0';


	free(s1);
	free(s2);
	free(s3);

	free(utf1);
	free(utf2);
	free(utf3);


//	return nombreLargo;
}

void ArmarEntradaNombreCortoNueva(char *entradaCorta, char *nombre, uint32_t posCluster, char atributo)
{
	memset(entradaCorta, 0, 32);
	strncpy(entradaCorta, nombre,11); // copia nombre en entrada si nombre es mas chico que 11, llena de null hasta 11
	//memcpy(entradaCorta, nombre, 11);
	*(entradaCorta + 11) = atributo;

	uint32_t alta, baja;

	obtenerParteBajaAltaDeCluster(posCluster, &alta, &baja);



	memcpy(entradaCorta + 20, &alta, 2);
	memcpy(entradaCorta + 26, &baja, 2);
}


void CrearEntradaDeSubcarpeta(char *subcarpeta, uint32_t *actual, uint32_t *padre)
{
	// Crea las entradas iniciales de todos los subdirectorios:
	// .	el cluster del directorio actual es "actual"
	// ..	el cluster del directorio padre es "padre"

	uint16_t altaActual, bajaActual, altaPadre, bajaPadre;

	*subcarpeta = '.';
	*(subcarpeta + 32) = '.';
	*(subcarpeta + 33) = '.';

	*(subcarpeta + 11) = ATRIBUTO_DIRECTORIO;
	*(subcarpeta + 11 + 32) = ATRIBUTO_DIRECTORIO;

	obtenerParteBajaAltaDeCluster(*actual, &altaActual, &bajaActual); //dir actual "."
	obtenerParteBajaAltaDeCluster(*padre, &altaPadre, &bajaPadre); //dir padre ".."

	memcpy(subcarpeta + 20, &altaActual, 2);
	memcpy(subcarpeta + 26, &bajaActual, 2);

	memcpy(subcarpeta + 20 + 32, &altaPadre, 2);
	memcpy(subcarpeta + 26 + 32, &bajaPadre, 2);

}

uint32_t esCarpetaVacia (uint32_t iClus) //iClus es el cluster a la entrada de directorio
{   //retorna 1, si es carpeta vacía. Retorna 0, si tiene archivos
	struct colaCluster *cola;
	uint32_t cantNodosCola, i, cantidadEntradas;
	char *carpeta;

	cola = CrearColaClusterDeEntradasDirectorio(iClus);
	cantNodosCola = CantidadDeNodosCola(cola);

	carpeta = calloc((cantNodosCola + 1) * TAMANO_CLUSTER, sizeof(char) );
	carpeta = ObternerCarpetaDeEntradasDeDirectorio(cola);

	cantidadEntradas = cantNodosCola * TAMANO_CLUSTER / 32; /* 32 tamaño de entradas */

	for (i = 2; i < cantidadEntradas; i++)
	// es desde i=2 porque 0 es "." y 1 es ".."
	{
		if ( *(carpeta +(i*32)) != ATRIBUTO_BORRADO1 && *(carpeta +(i*32)) != 0)
		{
			free(carpeta);
			return 0;
		}
		else
			if (*(carpeta +(i*32)) == 0)
			{
				free(carpeta);
				return 1;
			}
	}

	free (carpeta);
	return 1;
}

void borrarTodasLasEntradasDeCarpeta(uint32_t iclusCarpeta)
{
	struct colaCluster *cola;
	uint32_t iClus;
	char *cluster;

	cluster = calloc(TAMANO_CLUSTER, sizeof(char));

	cola = CrearColaClusterDeEntradasDirectorio(iclusCarpeta);

	while (!ColaClusterVacia(*cola))
	{
		iClus = SacarDeColaCluster(cola);
		enviarCluster(iClus, cluster, 0);
	}

	free(cluster);
}

char *obtenerNombreArchivoPath(char *path_original)
{
	char *nombre, *path, *pathAux;
//	nombre = (char *) malloc (50);
	path = (char *) malloc (strlen(path_original)+1);
	pathAux = (char *) malloc (strlen(path_original)+1);

	strcpy (path, path_original);


	nombre = strtok(path, "/");
	strcpy(pathAux, nombre);


	while (pathAux != NULL)
	{
		strcpy (nombre, pathAux);
		pathAux = strtok(NULL, "/");
	}


	free (pathAux);

	char *nombreADevolver;
	nombreADevolver = (char *) malloc (strlen(nombre)+1);
	strcpy (nombreADevolver, nombre);
//	free(nombre);
	free (path);
	return nombreADevolver;
}

void obtenerParteBajaAltaDeCluster(uint32_t posCluster, uint32_t *alta, uint32_t *baja)
{

	*alta = posCluster / 256; // 256 es 16*16
	*baja = posCluster % 256;

	/*
	*alta = posCluster << 16;
	*baja = posCluster;
	*/
}

void EscribirPosicion(char *entrada, uint32_t posicion)
{
	uint32_t alta, baja;

	obtenerParteBajaAltaDeCluster(posicion, &alta, &baja);

	memcpy(entrada + 20, &alta, 2);
	memcpy(entrada + 26, &baja, 2);
}

void limpiarClusterEnDisco(uint32_t numeroCluster)
{
	char *cluster;
	cluster = calloc (TAMANO_CLUSTER, sizeof(char));

	enviarCluster(numeroCluster, cluster, 0);
	free(cluster);
}
